using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using Microsoft.Practices.CompositeUI.SmartParts;
using Microsoft.Practices.CompositeUI.Utility;

namespace SCSFContrib.CompositeUI.WPF.Workspaces
{
	/// <summary>
	/// Implements an <see cref="IWorkspace"/> that displays smart parts in <see cref="Window"/>s.
	/// </summary>
	/// <remarks>
	/// <para>
	/// The <c>WindowWorkspace</c> displays smart parts with arbitrary <see cref="object"/> contents inside <see cref="Window"/>s. It accepts
	/// instances of <see cref="WindowSmartPartInfo"/> to tailor the <see cref="Window"/> that contains the shown smart part.
	/// </para>
	/// </remarks>
	/// <example>
	/// The following example shows how smart parts can be manipulated in a <c>WindowWorkspace</c>:
	/// <code>
	/// //show a smart part in a window
	/// _windowWorkspace.Show(smartPart1);
	///
	/// //show a smart part in a window titled 'Some Window'
	/// _windowWorkspace.Show(smartPart2, new WindowSmartPartInfo("Some Window"));
	///
	/// //show a smart part in a customized window
	/// WindowSmartPartInfo wspi = new WindowSmartPartInfo("Customized Window");
	/// wspi.IsModal = true;
	/// wspi.Width = 300;
	/// wspi.Height = 250;
	/// wspi.ShowInTaskbar = false;
	/// wspi.Icon = icon;
	/// wspi.StartupLocation = WindowStartupLocation.CenterOwner;
	/// wspi.Owner = ownerWindow;
	/// wspi.WpfStyle = Resources.Find("SomeStyle") as Style;
	/// _windowWorkspace.Show(smartPart3, wspi);
	/// </code>
	/// </example>
	public class WindowWorkspace : Workspace<object, WindowSmartPartInfo>
	{
		private readonly IDictionary<object, Window> _windows;

		/// <summary>
		/// Gets a read-only dictionary of the smart part to <see cref="Window"/> relationships maintained by this <c>WindowWorkspace</c>.
		/// </summary>
		public ReadOnlyDictionary<object, Window> Windows
		{
			get
			{
				return new ReadOnlyDictionary<object, Window>(_windows);
			}
		}

		/// <summary>
		/// Constructs an instance of <c>WindowWorkspace</c>.
		/// </summary>
		public WindowWorkspace()
		{
			_windows = new Dictionary<object, Window>();
		}

		/// <summary>
		/// Applies <paramref name="smartPartInfo"/> to the <see cref="Window"/> associated with <paramref name="smartPart"/>.
		/// </summary>
		/// <param name="smartPart">
		/// The smart part whose <see cref="Window"/> is to have <paramref name="smartPartInfo"/> applied to it.
		/// </param>
		/// <param name="smartPartInfo">
		/// The <see cref="WindowSmartPartInfo"/> to apply to the <see cref="Window"/> associated with
		/// <paramref name="smartPart"/>.
		/// </param>
		protected override void OnApplySmartPartInfo(object smartPart, WindowSmartPartInfo smartPartInfo)
		{
			Debug.Assert(_windows.ContainsKey(smartPart));
			smartPartInfo.ApplyTo(_windows[smartPart]);
		}

		/// <summary>
		/// Shows the <see cref="Window"/> associated with <paramref name="smartPart"/>.
		/// </summary>
		/// <param name="smartPart">
		/// The smart part whose associated <see cref="Window"/> is to be shown.
		/// </param>
		/// <param name="smartPartInfo">
		/// Any extra display information about the <see cref="Window"/>.
		/// </param>
		protected override void OnShow(object smartPart, WindowSmartPartInfo smartPartInfo)
		{
			Window window = CreateWindow(smartPart);
			smartPartInfo.ApplyTo(window);

			if (smartPartInfo.IsModal)
			{
				smartPartInfo.DialogResult = window.ShowDialog();
			}
			else
			{
				window.Show();
			}
		}

		/// <summary>
		/// Activates the <see cref="Window"/> associated with <paramref name="smartPart"/>.
		/// </summary>
		/// <param name="smartPart">
		/// The smart part whose associated <see cref="Window"/> is to be activated.
		/// </param>
		protected override void OnActivate(object smartPart)
		{
			Debug.Assert(_windows.ContainsKey(smartPart));
			_windows[smartPart].Activate();
		}

		/// <summary>
		/// Hides the <see cref="Window"/> associated with <paramref name="smartPart"/>.
		/// </summary>
		/// <param name="smartPart">
		/// The smart part whose associated <see cref="Window"/> is to be hidden.
		/// </param>
		protected override void OnHide(object smartPart)
		{
			Debug.Assert(_windows.ContainsKey(smartPart));
			_windows[smartPart].Hide();
		}

		/// <summary>
		/// Closes the <see cref="Window"/> associated with <paramref name="smartPart"/>.
		/// </summary>
		/// <param name="smartPart">
		/// The smart part whose associated <see cref="Window"/> is to be closed.
		/// </param>
		protected override void OnClose(object smartPart)
		{
			Debug.Assert(_windows.ContainsKey(smartPart));
			_windows[smartPart].Close();
			_windows.Remove(smartPart);
		}

		/// <summary>
		/// Creates a new instance of <see cref="WindowSmartPartInfo"/> and copies any relevant information from <paramref name="source"/> into
		/// it.
		/// </summary>
		/// <param name="source">
		/// The source smart part info.
		/// </param>
		/// <returns>
		/// A new instance of <see cref="WindowSmartPartInfo"/> containing any relevant details copied from <paramref name="source"/>.
		/// </returns>
		protected override WindowSmartPartInfo ConvertFrom(ISmartPartInfo source)
		{
			WindowSmartPartInfo windowSmartPartInfo = SmartPartInfo.ConvertTo<WindowSmartPartInfo>(source);
			WindowSmartPartInfo sourceWindowSmartPartInfo = source as WindowSmartPartInfo;

			if (sourceWindowSmartPartInfo != null)
			{
				sourceWindowSmartPartInfo.ApplyTo(windowSmartPartInfo);
			}

			return windowSmartPartInfo;
		}

		private Window CreateWindow(object smartPart)
		{
			Debug.Assert(!_windows.ContainsKey(smartPart));
			Window window = new Window();
			window.Content = smartPart;

			window.Closing += delegate(object sender, System.ComponentModel.CancelEventArgs e)
			{
				RaiseSmartPartClosing(e);
			};

			window.Closed += delegate
			{
				_windows[smartPart].Content = null;
				_windows.Remove(smartPart);
				InnerSmartParts.Remove(smartPart);
			};

			_windows[smartPart] = window;
			return window;
		}
	}
}